package cn.tedu.mall.order.security.filter;

import cn.tedu.mall.common.pojo.sso.authentication.CsmallAuthenticationInfo;
import cn.tedu.mall.common.utils.JwtTokenUtils;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.filter.OncePerRequestFilter;

/**
 * 通过请求头携带jwt票据,解析验证是否合法,如果合法,存储到spring security认证数据中
 */
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {
    @Autowired
    private JwtTokenUtils jwtTokenUtils;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;
    @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response,
        FilterChain filterChain) throws ServletException, IOException {
        //获取token值
        String token = getTokenFromHeader(request);
        if (ObjectUtils.isEmpty(token)){
            //存放一个没有认证权限的对象,或者不存放任何认证权限对象
            //filterChain.doFilter(request,response);//过滤器继续执行其他过滤器方法
            //为了测试方便,任何请求都有认证信息
            SecurityContext context = SecurityContextHolder.createEmptyContext();//构造空环境
            //将自定义info权限list转成认证对象权限
            List<GrantedAuthority> authorities=new ArrayList<>();
            authorities.add(new SimpleGrantedAuthority("ROLE_user"));
            //生成info相关的认证对象
            UsernamePasswordAuthenticationToken authentication=
                new UsernamePasswordAuthenticationToken("张三",null,authorities);
            context.setAuthentication(authentication);
            SecurityContextHolder.setContext(context);
            filterChain.doFilter(request,response);
            return;
        }else {
            //验证黑名单
            String blackListKey="mall:sso:black:list:token:";
            SetOperations<String, String> operations =
                stringRedisTemplate.opsForSet();
            if (operations.isMember(blackListKey,token)){
                filterChain.doFilter(request,response);
                return;
            }
            //token拿到了 使用jwtUtils解析
            //先获取 login用户信息
            CsmallAuthenticationInfo info=null;
            try{
                 info= jwtTokenUtils.getUserInfo(token);
                //拿到之后,我要把这里的信息,存放到spring security框架,使用
                //存放完了,相当于框架里存在认证对象 存放到spring securityContextHolder(底层是threadLocal)
                SecurityContext context = SecurityContextHolder.createEmptyContext();//构造空环境
                //将自定义info权限list转成认证对象权限
                List<GrantedAuthority> authorities=new ArrayList<>();
                for (String authority : info.getAuthorities()) {
                    SimpleGrantedAuthority simpleGrantedAuthority=new SimpleGrantedAuthority(authority);
                    authorities.add(simpleGrantedAuthority);
                }
                //生成info相关的认证对象
                UsernamePasswordAuthenticationToken authentication=
                    new UsernamePasswordAuthenticationToken(info.getUsername(),null,authorities);
                context.setAuthentication(authentication);
                SecurityContextHolder.setContext(context);
                filterChain.doFilter(request,response);
            }catch (Exception e){
                filterChain.doFilter(request,response);//过滤器继续执行其他过滤器方法
                return;
            }
        }
    }

    /**
     * 从请求拿到token
     * 1. 后台前端页面把token放到Bearer头里的,直接携带JWT
     * 2. 前台前端把jwt放到Authorization头的,同时jwt前缀叫做Bearer
     */
    private String getTokenFromHeader(HttpServletRequest request) {
        boolean allEmpty = false;
        //先从Bearer那
        String bearerToken = request.getHeader("Bearer");
        if (!ObjectUtils.isEmpty(bearerToken)) {
            return bearerToken;
        }
        String authorizationToken = request.getHeader("Authorization");
        if (!ObjectUtils.isEmpty(authorizationToken)) {
            String token=authorizationToken.substring(7);
            return token;
        }
        return null;

    }
}
